package logic

import (
	"io"
	"os"
	"os/exec"
	"path"
	"strings"
	"syscall"

	"gddgame.cc/galaxy/utils"
)

func ExecCommand(command string, args ...string) (string, error) {
	command = command + " " + strings.Join(args, " ") + "\n"
	cmd := exec.Command("/bin/sh", "-c", command)

	b, err := cmd.CombinedOutput()
	return string(b), err
}

func AttachCommand(command string, args ...string) error {
	command = command + " " + strings.Join(args, " ") + "\n"
	cmd := exec.Command("/bin/sh", "-c", command)

	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	if err := cmd.Start(); err != nil {
		return err
	}
	return cmd.Wait()
}

func ProcessInfo(pid int) (map[string]interface{}, error) {
	msg, err := ExecCommand("ps", "-p "+utils.ToString(pid)+" -l")
	if err != nil {
		return nil, err
	}
	info := make(map[string]interface{})
	lines := strings.Split(msg, "\n")
	pidIndex := -1
	cpuIndex := -1
	memIndex := -1
	for _, line := range lines {
		column := strings.Fields(line)
		if len(column) == 0 {
			continue
		}
		if pidIndex < 0 {
			for index, value := range column {
				v := strings.TrimSpace(utils.ToString(value))
				switch v {
				case "PID":
					pidIndex = index
				case "C":
					fallthrough
				case "CPU":
					cpuIndex = index
				case "RSS":
					memIndex = index
				}
			}
		} else {
			if cpuIndex >= 0 {
				info["cpu"] = utils.ToString(column[cpuIndex]) + "%"
			}
			if memIndex >= 0 {

				info["mem"] = utils.ToInt(column[memIndex])
			}
			break
		}

	}
	return info, nil
}

func ProcessStat(pid int) (map[string]interface{}, error) {
	msg, err := ExecCommand("cat", "/proc/"+utils.ToString(pid)+"/status")
	if err != nil {
		return nil, err
	}
	status := make(map[string]interface{})
	lines := strings.Split(msg, "\n")
	for _, line := range lines {
		if strings.HasPrefix(line, "VmRSS") {
			column := strings.Split(line, ":")
			value := strings.Replace(strings.Replace(column[1], " ", "", -1), "\t", "", -1)
			if strings.HasSuffix(value, "kB") {
				status["mem"] = utils.ToInt(strings.Replace(value, "kB", "", 1))
			} else if strings.HasSuffix(value, "mB") {
				status["mem"] = utils.ToInt(strings.Replace(value, "mB", "", 1)) * 1024
			} else if strings.HasSuffix(value, "gB") {
				status["mem"] = utils.ToInt(strings.Replace(value, "gB", "", 1)) * 1024 * 1024
			}

			break
		}
	}
	return status, nil
}

func StartProcess(log io.WriteCloser, workDir string, additionalEnv []string, command string, args ...string) (int, error) {
	cmd := exec.Command(command, args...)
	cmd.Stdin = nil
	cmd.Stdout = nil
	cmd.Stderr = nil
	cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
	if workDir != "" {
		cmd.Dir = workDir
	}

	if additionalEnv != nil {
		newEnv := append(os.Environ(), additionalEnv...)
		cmd.Env = newEnv
	}
	cmd.Stdout = log
	cmd.Stderr = log

	if err := cmd.Start(); err != nil {
		return -1, err
	}
	pid := cmd.Process.Pid
	//_ = cmd.Process.Release()
	go func() {
		_ = cmd.Wait()
		_ = log.Close()
	}()
	return pid, nil
}

func StopProcess(pid int) error {
	return syscall.Kill(pid, syscall.SIGTERM)
}

func FindProcess(pid int) bool {
	if err := syscall.Kill(pid, 0); err == nil {
		return true
	}
	//result, err := ExecCommand("ps", "-ax | awk '{ print $1 }' | grep -e \"^"+utils.ToString(pid)+"$\"")
	//if err != nil {
	//	return false
	//}
	//if result != "" {
	//	return true
	//}
	return false
}

func decompression(file string, targetDir string) error {
	if err := utils.Mkdir(targetDir); err != nil {
		return err
	}
	ext := path.Ext(file)
	var command string
	var args []string
	if ext == "tar" {
		command = "tar"
		args = []string{"-zxf", file, "-C", targetDir}
	} else if ext == "tar.gz" {
		command = "tar"
		args = []string{"-zxf", file, "-C", targetDir}
	} else if ext == "zip" {
		command = "unzip"
		args = []string{"unzip", file, "-d", targetDir}
	}
	if err := AttachCommand(command, args...); err != nil {
		// 删除工作目录
		if err := os.RemoveAll(targetDir); err != nil {
			return err
		}
		return err
	}
	return nil
}
